﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;

namespace Vkontakte.Api
{
	public sealed class LongPollServerClient
	{
		private LongPollServerData _data;
		private HttpWebRequest _currentRequest;
		public LongPollServerClient()
		{
	
		}

		private void Begin()
		{
			_currentRequest = (HttpWebRequest)WebRequest.Create(Utils.GetLongPollUri(_data));
			_currentRequest.BeginGetResponse(RequestCallback, null);
		}

		public void Start(LongPollServerData data)
		{
			_data = data;
			Begin();
		}

		private void RequestCallback(IAsyncResult result)
		{
			string temp = "";
			bool failed = false;
			string array = null;

			WebResponse responce = null;
			Stream stream = null;
			StreamReader reader = null;
			try
			{

				responce = _currentRequest.EndGetResponse(result);
				stream = responce.GetResponseStream();
				reader = new StreamReader(stream);
				string answer = reader.ReadToEnd();
				int end = answer.LastIndexOf('}');
				temp = answer.Substring(1, end - 1);
			}catch(Exception)
			{
				
			}
			finally
			{
				if (reader != null)
				{
					reader.Close();
				}
				if (stream != null)
				{
					stream.Close();
				}
				if (responce!=null)
				{
					responce.Close();
				}
				
			}
			if (string.IsNullOrEmpty(temp)||( !temp.StartsWith("\"ts\"" )))
			{
				failed = true;
				if (Failed!=null)
				{
					Failed();
				}
			}
			else
			{
				int startTs = temp.IndexOf( ':' );
				int endTs = temp.IndexOf( ',', startTs );
				string strTs = temp.Substring( startTs + 1, endTs - startTs -1 );
				_data.Timestamp = long.Parse( strTs );
				array = temp.Substring(endTs + 1);
				startTs = array.IndexOf('[');
				endTs = array.LastIndexOf(']');
				array = array.Substring(startTs + 1, endTs - startTs - 1);
			}
	
			if (!failed)
			{
				Begin();
				ParseAnswer(array);
			}
			
		}

		private void ParseAnswer( string answer )
		{

			if (answer=="")
			{
				return;
			}
			try
			{

				string[] parts = answer.Split( new string[] {"],["}, StringSplitOptions.None );
				parts[ 0 ] = parts[ 0 ].Remove( 0, 1 );
				parts[ parts.Length - 1 ] = parts[ parts.Length - 1 ].Remove( parts[ parts.Length - 1 ].Length - 1 );
				for ( int i = 0; i < parts.Length; i++ )
				{
					int pos = parts[ i ].IndexOf( ',' );
					int code = int.Parse( parts[ i ].Substring( 0, pos ) );
					int pos2;
					string uid;
					long userId;
					long messageId;
					long timestamp;
					string subject;
					string message;
					switch (code)
					{
						// Удаление сообщения
						case 0:
							break;
						// Новое сообщение
						case 4:
							pos2 = parts[i].IndexOf(',', pos + 1);
							uid = parts[i].Substring(pos + 1, pos2 - pos - 1);
							messageId = long.Parse(uid);
							//
							pos = parts[i].IndexOf(',', pos2 + 1);
							uid = parts[i].Substring(pos2 + 1, pos - pos2 - 1);
							LongPollMessageFlags flags = (LongPollMessageFlags)int.Parse(uid);
							//
							pos2 = parts[i].IndexOf(',', pos + 1);
							uid = parts[i].Substring(pos + 1, pos2 - pos - 1);
							userId = long.Parse(uid);
							//
							pos = parts[i].IndexOf(',', pos2 + 1);
							uid = parts[i].Substring(pos2 + 1, pos - pos2 - 1);
							timestamp = long.Parse(uid);
							//
							pos2 = parts[i].IndexOf('"', pos);
							pos = parts[i].IndexOf('"', pos2 + 1);
							subject = parts[i].Substring(pos2 + 1, pos - pos2 - 1);
							//
							pos2 = parts[i].IndexOf('"', pos + 1);
							pos = parts[i].IndexOf('"', pos2 + 1);
							message = parts[i].Substring(pos2 + 1, pos - pos2 - 1);
							string[] split= message.Split(new string[] {"<*>"}, StringSplitOptions.None);
							message = split[0];
							string media = null;
							if (split.Length>1)
							{
								media = split[1];
							}
							message = message.Replace("<br>", "\n").Replace("\\/", "/").Replace("\\\\", "\\").Replace("&amp;", "&").Replace("&lt", "&lt");
	
							if (NewMessage != null)
							{
								NewMessage(messageId, flags,userId, timestamp, subject, message,media);
							}
							break;
						// Пользователь стал онлайн
						case 8:
						
							pos2 = parts[i].IndexOf(',', pos + 1);
							uid = parts[i].Substring(pos + 2, pos2 - pos - 2);
							userId = long.Parse(uid);
							if (UserOnline != null)
							{
								UserOnline(userId);
							}
							break;
						// Пользователь стал оффлайн
						case 9:
							pos2=parts[i].IndexOf( ',',pos+1 );
							uid = parts[i].Substring(pos + 2, pos2 - pos-2);
							userId = long.Parse(uid);
							if (UserOffline != null)
							{
								UserOffline(userId);
							}
							break;
						default:
							break;
					}
				}
			}catch(Exception)
			{
				
			}
		}
		public event Action<long, LongPollMessageFlags, long,long, string, string,string> NewMessage;
		public event Action<long> UserOnline;
		public event Action<long> UserOffline;
		public event Action Failed;
	}

	[Flags]
	public enum LongPollMessageFlags
	{
		None=0,
		/// <summary>
		/// сообщение непрочитано
		/// </summary>
		Unread=1,
		/// <summary>
		/// исходящее сообщение
		/// </summary>
		Outbox=2,
		/// <summary>
		/// на сообщение был создан ответ
		/// </summary>
		Replied=4,
		/// <summary>
		/// помеченное сообщение
		/// </summary>
		Impotant=8,
		/// <summary>
		/// сообщение отправлено через чат
		/// </summary>
		Chat=16,
		/// <summary>
		/// сообщение отправлено другом
		/// </summary>
		Friends=32,
		/// <summary>
		/// сообщение помечено как "Спам"
		/// </summary>
		Spam=64,
		/// <summary>
		/// сообщение удалено (в корзине)
		/// </summary>
		Deleted=128,
		/// <summary>
		/// сообщение проверено пользователем на спам
		/// </summary>
		Fixed=256,
		/// <summary>
		/// сообщение содержит медиаконтент 
		/// </summary>
		Media=512
	}
}
